/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 *
 */

import { noop } from '@baize/wdk';
import { MetricFactory, MetricLogType } from '@ohos/hvigor';
import fs from 'fs';
import fse from 'fs-extra';
import path from 'path';
import util from 'util';

import { PackingToolOptions } from '../../builder/inner-java-command-builder/packing-tool-options.js';
import { BuildArtifactExtension, BuildDirConst } from '../../const/build-directory-const.js';
import { CommonConst } from '../../const/common-const.js';
import { DeviceTypeConst } from '../../const/device-type-const.js';
import { FileUtil } from '../../utils/file-util.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';
import { ProcessUtils } from '../../utils/process-utils.js';
import { TaskNames } from '../common/task-names.js';
import { ModuleTaskService } from '../service/module-task-service.js';
import { TargetTaskService } from '../service/target-task-service.js';
import { OhosHapTask } from '../task/ohos-hap-task.js';

import { LegacySyscapTransform } from './legacy-syscap-transform.js';

/**
 * 生成lite的资源文件
 */
export class LegacyGenLiteSource extends OhosHapTask {
  private _logger: OhosLogger = OhosLogger.getLogger(LegacyGenLiteSource.name);
  protected syscapJsonPath: string | undefined;

  constructor(taskService: TargetTaskService) {
    super(taskService, TaskNames.LegacyFATask.GENERATE_LITE_CODE);
  }

  initTaskDepends() {
    this.declareDepends('LegacyCompileLiteJS');
    this.syscapJsonPath = path.resolve(this.moduleModel?.getSourceRootByTargetName(this.targetName), CommonConst.SYSCAP_JSON);
    if (fs.existsSync(this.syscapJsonPath!)) {
      this.declareDepends(LegacySyscapTransform.name);
    }
  }

  protected async doTaskAction(): Promise<void> {
    const relatedEntryModules = this.service.getRelatedEntryModules();
    const moduleType = this.service.getModuleModel().getModuleType();
    if (ModuleTaskService.checkEntryModules(moduleType, relatedEntryModules)) {
      for (const entryName of relatedEntryModules!) {
        await this.genLiteSource(entryName);
      }
    } else {
      await this.genLiteSource();
    }
  }

  private async genLiteSource(entryName = '') {
    const pathInfo = this.pathInfo;

    // copy js assets
    const assets = path.resolve(pathInfo.getIntermediatesLiteSource(), 'assets');
    const faAssetsPath = pathInfo.getInterMediatesLoaderOutLitePath();
    await fse.copy(faAssetsPath, assets);

    // copy config.json
    const compiledJson = path.resolve(pathInfo.getIntermediatesRes(), entryName, 'config.json');
    const destJson = path.resolve(pathInfo.getIntermediatesLiteSource(), entryName, 'config.json');
    await fse.ensureDir(path.resolve(pathInfo.getIntermediatesLiteSource(), entryName));

    if (this.targetData.isSingleDeviceTypeTarget()) {
      await fse.copyFile(compiledJson, destJson);
    } else {
      // 跨设备场景时，将config.json中的deviceType改为纯瘦设备类型
      const deviceType = this.targetData.getTargetDeviceType().filter((deviceType) => DeviceTypeConst.LITE_DEVICES.includes(deviceType));
      const config = fse.readJsonSync(compiledJson);
      config.module.deviceType = deviceType;

      await fse.outputJSON(destJson, config);
    }

    // copy res and bin file
    const srcResources = path.resolve(pathInfo.getIntermediatesRes(), entryName, BuildDirConst.RESTOOL_BUILD_RESOURCES);
    const destResources = path.resolve(assets, this.module.getName(), entryName, BuildDirConst.RESTOOL_BUILD_RESOURCES);

    await fse.ensureDir(path.resolve(assets, this.module.getName(), entryName));
    await fse.copy(srcResources, destResources);
    await fse.copy(pathInfo.getIntermediatesLiteBinSource(), destResources);

    // copy resource.index
    const srcResIndex = path.resolve(pathInfo.getIntermediatesRes(), entryName, 'resources.index');
    const destResIndex = path.resolve(assets, this.module.getName(), entryName, 'resources.index');

    await fse.ensureDir(path.resolve(assets, this.module.getName(), entryName));
    await fse.copyFile(srcResIndex, destResIndex);

    // OH瘦设备打包的SysCap
    const srcRpcidSc = path.resolve(pathInfo.getIntermediatesSysCap(), CommonConst.RPCID_SC);
    const destRpcidSc = path.resolve(pathInfo.getIntermediatesLiteSource(), entryName, CommonConst.RPCID_SC);
    if (fse.existsSync(srcRpcidSc)) {
      await fse.copyFile(srcRpcidSc, destRpcidSc);
    }

    const targetData = this.targetService.getTargetData();
    if (this.targetService.needPackBin(targetData)) {
      const subTaskName = 'generate BIN packaging command';
      const subDurationEvent = this.durationEvent.createSubEvent(subTaskName, '');
      subDurationEvent.start();

      const packingToolOptions = new PackingToolOptions();
      packingToolOptions.addCalledJarFile(this.sdkInfo.getHapTobin());
      packingToolOptions
        .addProjectPath(pathInfo.getIntermediatesLiteSource())
        .addBinPath(path.resolve(pathInfo.getModuleBinOutput(), this.targetData.getModuleTargetOutputFileName('', false, BuildArtifactExtension.DOT_BIN)));
      MetricFactory.createLogEvent(util.format(packingToolOptions.build()), MetricLogType.DEBUG);
      this._logger.debug(packingToolOptions.build());
      FileUtil.checkDirWithoutDelete(pathInfo.getModuleBinOutput());
      const inputData = {
        moduleName: this.moduleName,
        commandLine: packingToolOptions.build(),
      };

      subDurationEvent.stop();
      subDurationEvent.setLog(subTaskName, MetricLogType.INFO);
      const submitTaskName = 'submit BIN packaging task to work pool';
      const subToolDurationEvent = this.durationEvent.createSubEvent(submitTaskName, '');
      subToolDurationEvent.start();

      await new ProcessUtils(inputData.moduleName).submitExecutionWithoutReturn(this, this.getWorkerPool(), inputData, noop, [], subToolDurationEvent);

      subToolDurationEvent.stop();
      subToolDurationEvent.setLog(submitTaskName, MetricLogType.INFO);
    }
  }

  protected async beforeTask() {
    await fse.emptydir(this.pathInfo.getIntermediatesLiteSource());
  }
}
